package fr.lip6.meta.ple.generation.aspectj;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.gmt.modisco.java.AbstractTypeDeclaration;
import org.eclipse.gmt.modisco.java.BodyDeclaration;
import org.eclipse.gmt.modisco.java.ClassDeclaration;
import org.eclipse.gmt.modisco.java.ConstructorDeclaration;
import org.eclipse.gmt.modisco.java.MethodDeclaration;
import org.eclipse.gmt.modisco.java.Model;
import org.eclipse.gmt.modisco.java.emf.impl.ClassDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ConstructorDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.FieldDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.MethodDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.PackageImpl;

import artefact.umlClassDiagram.CreateAttribute;
import artefact.umlClassDiagram.CreateClass;
import artefact.umlClassDiagram.CreateOperation;
import artefact.umlClassDiagram.CreateOperationRefinement;
import artefact.umlClassDiagram.CreatePackage;
import fr.lip6.meta.ple.featureIdentification.Feature;
import fr.lip6.meta.ple.generation.strategy.GenerateFromXmiStrategy;
import fr.lip6.meta.tools.*;

public class GenerateFromXmiAJ extends GenerateFromXmiStrategy {
	public static ClassDeclarationImpl getClassDeclaration(String path, String packagename, String classname) {
		PackageImpl pckg = readpackage(path, packagename);
		Iterator<AbstractTypeDeclaration> typeDecls = pckg.getOwnedElements().iterator();
		 
		while (typeDecls.hasNext()) {
			AbstractTypeDeclaration typeDecl = typeDecls.next();
			
			if (typeDecl instanceof ClassDeclaration) {
				ClassDeclarationImpl classDecl = (ClassDeclarationImpl) typeDecl;

				if (classDecl.getName().equals(classname)) {
					return classDecl;
				}
			}
		}

		return null;
	}

	public static FieldDeclarationImpl getFieldDeclaration(String path, String packagename, String classname, String fieldname) {
		FieldDeclarationImpl fd = null;
		ClassDeclarationImpl d = getClassDeclaration(path, packagename, classname);
		EList<BodyDeclaration> bodys = d.getBodyDeclarations();
		
		// reads body declaration
		for(BodyDeclaration bo : bodys) {
			if(bo instanceof FieldDeclarationImpl) {
				FieldDeclarationImpl fd1 = (FieldDeclarationImpl) bo;

				if(fd1.getFragments().get(0).getName().equals(fieldname)) {
					fd = fd1;
					break;
				}
			}
		}

		return fd;
	}

	public static MethodDeclarationImpl getMethoddeclaration(String path, String packagename, String classname, String methodname) {
		MethodDeclarationImpl methodDecl = null;
		ClassDeclarationImpl classDecl = getClassDeclaration(path, packagename, classname);
		EList<BodyDeclaration> bodyDecls = classDecl.getBodyDeclarations();
		
		//read body declaration 
		for(BodyDeclaration bo : bodyDecls) {
			if (bo instanceof MethodDeclaration) {
				MethodDeclarationImpl m1 = (MethodDeclarationImpl) bo;
				if(m1.getName().equals(methodname)) {
					methodDecl = m1;
					break;
				}
			}
		}

		return methodDecl;
	}
	
	
	public static	List<MethodDeclaration> getOperations(Feature f,String packagename,String classname)
	{
		ArrayList<MethodDeclaration> list=new ArrayList<MethodDeclaration>();
		
		for(Trigger t : f)
		{
			StatementPrimitive st = (StatementPrimitive)t;
			if (st.getPrimitive() instanceof CreateOperation){
				CreateOperation c=(CreateOperation) st.getPrimitive();
				String [] lien=c.getLien().split("::");
				if(c.getOwener().equals(classname) && packagename.equals(lien[1]))
					{
					if(!(c.getOwener().equals(c.getName())))
					{
						
				 MethodDeclaration fd	=getMethoddeclaration(lien[0], packagename, classname, c.getName());
					
					list.add(fd);
					}
					
					
					
					}
				
			}
		}
		return list;

	}
	
	public static	List<MethodDeclaration> getRefinementoperations(Feature f,String packagename,String classname)
	{
		ArrayList<MethodDeclaration> list=new ArrayList<MethodDeclaration>();
		
		for(Trigger t : f)
		{
			StatementPrimitive st = (StatementPrimitive)t;
			if (st.getPrimitive() instanceof CreateOperationRefinement){
				CreateOperationRefinement c=(CreateOperationRefinement) st.getPrimitive();
				String [] lien=c.getLien().split("::");
				if(c.getOwner().equals(classname) && packagename.equals(lien[1]))
					{
					if(!(c.getOwner().equals(c.getName())))
					{
						
				 MethodDeclaration fd	=getMethoddeclaration(lien[0], packagename, classname, c.getName());
					
					list.add(fd);
					}
					
					
					
					}
				
			}
		}
		return list;

	}
	
	
	
	
	
	public static ConstructorDeclarationImpl getConstructorDeclaration(String pathe,String packagename,String classname,String methodname)
	{
		ConstructorDeclarationImpl m=null;
		
		ClassDeclarationImpl d = getClassDeclaration(pathe, packagename, classname);
		EList<BodyDeclaration> bodys=d.getBodyDeclarations();
		//read body declaration 
		for(BodyDeclaration bo:bodys)
		{
			
			if (bo instanceof ConstructorDeclaration)
			{
				ConstructorDeclarationImpl m1= (ConstructorDeclarationImpl) bo;
				 if(m1.getName().equals(methodname))
				 {
					 m=m1;break;
				 }
			
			}
		}
		
		return m;
	}
	
	public static	ArrayList<ConstructorDeclarationImpl> getConstructorsDeclaration(Feature f,String packagename,String classname)
	{
		ArrayList<ConstructorDeclarationImpl> list=new ArrayList<ConstructorDeclarationImpl>();
		
		for(Trigger t : f)
		{
			StatementPrimitive st = (StatementPrimitive)t;
			if (st.getPrimitive() instanceof CreateOperation){
				CreateOperation c=(CreateOperation) st.getPrimitive();
				String [] lien=c.getLien().split("::");
				if(c.getOwener().equals(classname) && packagename.equals(lien[1]))
					{
					if((c.getOwener().equals(c.getName())))
					{
						
						ConstructorDeclarationImpl fd	=getConstructorDeclaration(lien[0], packagename, classname, c.getName());
					
					list.add(fd);
					}
					
					
					
					}
				
			}
		}
		return list;

	}
	
	
	
	public static List<FieldDeclarationImpl> getFieldsDeclaration(Feature feat, String packagename, String classname) {
		ArrayList<FieldDeclarationImpl> list = new ArrayList<FieldDeclarationImpl>();

		for(Trigger t : feat) {
			StatementPrimitive st = (StatementPrimitive) t;
			
			if (st.getPrimitive() instanceof CreateAttribute){
				CreateAttribute c = (CreateAttribute) st.getPrimitive();
				String [] lien = c.getLien().split("::");

				if(c.getOwner().equals(classname) && packagename.equals(lien[1])) {
					FieldDeclarationImpl fd = getFieldDeclaration(lien[0], packagename, classname, c.getName());

					list.add(fd);
				}
			}
		}
		
		return list;
	}

	public static List<ClassDeclaration> getClassDeclarations(Feature feat, String packagename) {
		ArrayList<ClassDeclaration> list = new ArrayList<ClassDeclaration>();

		for(Trigger tr : feat) {
			StatementPrimitive st = (StatementPrimitive) tr;
			
			if (st.getPrimitive() instanceof CreateClass) {
				CreateClass crClass = (CreateClass) st.getPrimitive();

				if (crClass.getOwener().equals(packagename)) {
					ClassDeclarationImpl classDecl = getClassDeclaration(crClass.getLien(), packagename, crClass.getName());
					Iterator<BodyDeclaration> bodyDecls = classDecl.getBodyDeclarations().iterator();
					
					while(bodyDecls.hasNext()) {
						classDecl.getBodyDeclarations().remove(0);
					}
					
					Iterator<FieldDeclarationImpl> fieldDecls = getFieldsDeclaration(feat, packagename, crClass.getName()).iterator();

					while(fieldDecls.hasNext()) {
						FieldDeclarationImpl fd = fieldDecls.next();
						classDecl.getBodyDeclarations().add(fd);
					}
					
					Iterator<ConstructorDeclarationImpl> consDecls = getConstructorsDeclaration(feat, packagename, crClass.getName()).iterator();

					while(consDecls.hasNext()) {
						ConstructorDeclarationImpl fd1 = (ConstructorDeclarationImpl) consDecls.next();
						System.out.println("GenerateFromXMI.getClassDeclarations(): constructor is "+fd1.getName());
						classDecl.getBodyDeclarations().add(fd1);
					}

					Iterator<MethodDeclaration> ops = getOperations(feat, packagename, crClass.getName()).iterator();

					while(ops.hasNext()) {
						MethodDeclarationImpl methodDecl = (MethodDeclarationImpl) ops.next();
						System.out.println("GenerateFromXMI.getClassDeclarations(): method is "+methodDecl.getName());
						classDecl.getBodyDeclarations().add(methodDecl);
					}
					
					Iterator<MethodDeclaration> refOps = getRefinementoperations(feat, packagename, crClass.getName()).iterator();

					while(refOps.hasNext()) {
						MethodDeclarationImpl methodDecl = (MethodDeclarationImpl) refOps.next();
						System.out.println("GenerateFromXMI.getClassDeclarations(): method is "+methodDecl.getName());
						classDecl.getBodyDeclarations().add(methodDecl);
					}

					list.add(classDecl);
					System.out.println("GenerateFromXMI.getClassDeclarations(): class name is "+classDecl.getName());
				}
			}
		}

		return list;
	}
	
	public void generateProduct(Feature feat) {
		System.out.println("save model");
		Model model1 = loadModiscoJavaModel("Product1Bank_java.xmi");
		int elementnum = 0;

		model1.getOwnedElements().remove(0);

		while(elementnum< model1.getCompilationUnits().size()) {
			model1.getCompilationUnits().remove(0);	
		}

		for(Trigger t : feat) {
			StatementPrimitive st = (StatementPrimitive)t;
			
			if (st.getPrimitive() instanceof CreatePackage) {
				CreatePackage createPackage = (CreatePackage) st.getPrimitive();
				String name = createPackage.getName();
				String path = createPackage.getLien();
				PackageImpl pckg = readpackage(path, name);
				Iterator<AbstractTypeDeclaration> list = pckg.getOwnedElements().iterator();
				
				while(list.hasNext()) {
					pckg.getOwnedElements().remove(0);
				}

				/*Iterator<ClassDeclaration> fds = */
				getClassDeclarations(feat, createPackage.getName()).iterator();
			}
		}
		
		model1.setName("featureProduct1");
		/*ResourceSet rs = (ResourceSet) */
		save1(model1, new File("f1.xmi"));
		//generateJava("mop1.xmi", "C:\\test", rs);
		System.err.println("save model end");
	}
}